Ehcache 初探(在项目中的简单使用)

人点击

最近在开发一个android项目,项目是面向在校大学生的,据说推广起来,访问量必将很大,针对这种情况,再看看我们现在有的后台服务框架,竟然没有针对高访问量这种情况的处理,这里必定用到缓存技术,现有的框架中也最多存在Hibernate缓存的使用,但针对数据层的缓存,必然会用到Hibernate的二级缓存,竟然框架中连Hibernate的二级缓存都没用过,看到这些,想想也没有在现有的基础上做简单扩展的必要了,于是决定针对后台服务缓存这层进行研究使用。

在网上看到了不少缓存技术,有些比较陌生,有些不适合现有项目,还有些使用上不是很方便,最终确定选择了ehcache,发现Hibernate的二级缓存就是使用Ehcache实现的,但毕竟是嵌套在Hibernate框架中的,使用的灵活性就大打折扣了,例如Hibernate的二级缓存对于查询列表只能针对固定不变的结果数据进行缓存,另外不支持对缓存的动态添加修改,Ehcache本身单独就是很强大,于是决定单独提出来使用。

Ehcache 是现在最流行的纯Java开源缓存框架,配置简单、结构清晰、功能强大。

关于Ehcache原理性的东西这边就不做详细的记录了,毕竟也是刚刚接触,理解的多会有偏差,记录下一篇比较详细的文章供以后参考:

http://raychase.iteye.com/blog/1545906

下面介绍项目中Ehcache的简单使用。

前期准备

项目现有环境,eclipse开发,spring4.0

1、从官网上下载Ehcache最新版本ehcache-2.8.3-distribution,解压文件将lib下的三个jar包 拷到项目中(明显看到所需jar包都很小)

2、将ehcache.xml文件考到项目src根目录下
文件配置

ehcache.xml文件配置

增加cache节点,这里由于项目需求,设置最大缓存数量maxElementsInMemory为100000,过期设置为永不过期,因为过期数据需手动处理,

1
2
3
4
5
6
7
8
9
10
11
12
<cachename="jobInfoListCache"
maxElementsInMemory="100000" //最大缓存数量
eternal="true" //永不过期,手动处理过期数据
overflowToDisk="false"> //内存超出时不放到磁盘
<searchableallowDynamicIndexing="true">
<searchAttributename="positionTitle"expression="value.getPositionTitle()"/>
<searchAttributename="cityCode" expression="value.getCityCode()"/>
<searchAttributename="distinctCode"expression="value.getDistinctCode()"/>
<searchAttributename="positionTypeId"expression="value.getPositionTypeId()"/>
<searchAttributename="releaseTime"expression="value.getReleaseTime()"/>
</searchable>
</cache>

applicationContext-services.xml文件配置

<beanid="cacheManager"
   class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
   <propertyname="configLocation"value="classpath:ehcache.xml"/>
    <propertyname="shared" value="true"/>
</bean>
<!-- 配置一个缓存处理接口类-->
<beanid="jobInfoCacheManager"class="com.quangao.service.cacheManager.JobInfoCacheManager">
    <propertyname="cacheManager"ref="cacheManager"/>
    <propertyname="_dao" ref="GenericDao" />
</bean>

JobInfoCacheManager 文件具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
package com.quangao.service.cacheManager;

import java.util.ArrayList;
import java.util.List;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.search.Attribute;
import net.sf.ehcache.search.Direction;
import net.sf.ehcache.search.Query;
import net.sf.ehcache.search.Result;
import net.sf.ehcache.search.Results;

import com.quangao.dao.generic.GenericDao;
import com.quangao.model.Enum.EnumStatusType;
import com.quangao.model.jobposition.TJobPosition;
import com.quangao.util.StringUtil;

public class JobInfoCacheManager {

private CacheManagercacheManager;

private GenericDao _dao;

private final String attrNames[] = {"positionTitle", "cityCode","distinctCode","positionTypeId", "releaseTime" };
/**
* 获取职位列表
*
* @return
*/
public List<TJobPosition> getTJobPositions()
{
String hql = "fromTJobPosition where 1=1 and handleStatusId='"
+ EnumStatusType.FB.getKey() +"' order by releaseTime desc";
return_dao.getHql(hql);
}

/**
*
* 初始化职位列表缓存
*
*/
public void initJobInfoCache()
{
Cache cache = cacheManager.getCache("jobInfoListCache");
// 初始化列表数据
List<TJobPosition> jobPositions = getTJobPositions();
if (jobPositions !=null && jobPositions.size() > 0)
{
TJobPosition tJobPosition = null;
for (int i = 0; i < jobPositions.size(); i++)
{
tJobPosition = jobPositions.get(i);
Element element = new Element(tJobPosition.getId(),
tJobPosition);
cache.put(element);
}
}

// 动态注册搜索项,不起作用,研究中
//cache.registerDynamicAttributesExtractor(new
//DynamicAttributesExtractor() {
// public Map<String,Object> attributesFor(Element element) {
// Map<String, Object> attrs= new HashMap<String, Object>();
// TJobPosition value =(TJobPosition)element.getObjectValue();
// attrs.put(attrNames[0],value.getPositionTitle());
// attrs.put(attrNames[1],value.getCityCode());
// attrs.put(attrNames[2],value.getDistinctCode());
// attrs.put(attrNames[3],value.getPositionTypeId());
// return attrs;
// }
// });
}

/**
* 增加职位缓存
*
* @param tJobPosition
*/
public void addJobInfoCache(TJobPosition tJobPosition)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
if (tJobPosition !=null)
{
Element element = new Element(tJobPosition.getId(), tJobPosition);
cache.put(element);
}
}

/**
* 修改职位缓存
*
* @param tJobPosition
*/
public void updateJobInfoCache(TJobPosition tJobPosition)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
if (tJobPosition !=null)
{
// 相同key值,内容会被覆盖
Element element = new Element(tJobPosition.getId(), tJobPosition);
cache.put(element);
}
}

/**
* 移除职位缓存
*
* @param tJobPosition
*/
public void removeJobInfoCache(TJobPosition tJobPosition)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
if (tJobPosition !=null)
{
cache.remove(tJobPosition.getId());
}
}

/**
* 根据条件查询缓存列表
*
* @param cityCode
* @param areaCode
* @param typeCode
* @param firstResult
* @param maxResult
* @return
*/
public List<TJobPosition>getJobPositionsByCondition(String positionTitle,
String cityCode, String areaCode, String typeCode,
Integer firstResult, Integer maxResult)
{
Cache cache = cacheManager.getCache("jobInfoListCache");
List<TJobPosition> listTJobPositions = newArrayList<TJobPosition>();


/**
*
* 这是新版本的强大之处,可以根据缓存值对象进行条件查询,前提是在ehcache.xml文件中对值对象查询字段进行定义搜索项
*<searchableallowDynamicIndexing="true">
<searchAttributename="positionTitle"expression="value.getPositionTitle()"/>
<searchAttribute name="cityCode"expression="value.getCityCode()"/>
<searchAttribute name="distinctCode"expression="value.getDistinctCode()"/>
<searchAttribute name="positionTypeId"expression="value.getPositionTypeId()"/>
<searchAttribute name="releaseTime"expression="value.getReleaseTime()"/>
</searchable>
*/
Attribute<String> positionTitlet = cache
.getSearchAttribute(attrNames[0]);
Attribute<String> cityCodet = cache.getSearchAttribute(attrNames[1]);
Attribute<String> areaCodet = cache.getSearchAttribute(attrNames[2]);
Attribute<String> typeCodet = cache.getSearchAttribute(attrNames[3]);
Attribute<String> releaseTime =cache.getSearchAttribute(attrNames[4]);
// 查询结果集
Results results = null;
// 新建缓存值查询
Query query = cache.createQuery().includeValues();
// 根据条件索引
if (StringUtil.isNotBlankOrNull(positionTitle))
{
query.addCriteria(positionTitlet.ilike("*" +positionTitle +"*"));
}
if (StringUtil.isNotBlankOrNull(cityCode))
{
query.addCriteria(cityCodet.eq(cityCode));
}
if (StringUtil.isNotBlankOrNull(areaCode))
{
query.addCriteria(areaCodet.eq(areaCode));
}
if (StringUtil.isNotBlankOrNull(typeCode))
{
query.addCriteria(typeCodet.eq(typeCode));
}
// 查询结果排序
query.addOrderBy(releaseTime, Direction.DESCENDING).end();
results = query.execute();
// 分页查找
// List<Result>listreResults = results.all();
List<Result> listreResults = results.range(firstResult,maxResult);

// 将结果封装成需要的数据格式
if (listreResults !=null && listreResults.size() > 0)
{
Result result = null;
for (int i = 0; i < listreResults.size(); i++)
{
result = listreResults.get(i);

System.out.println("+++++++++++" + result.toString());

listTJobPositions.add((TJobPosition)result.getValue());
}
}
System.out.println("===============" + results.size());
return listTJobPositions;
}

public GenericDao get_dao()
{
return_dao;
}

public void set_dao(GenericDao dao)
{
_dao = dao;
}

public CacheManager getCacheManager()
{
returncacheManager;
}

public void setCacheManager(CacheManager cacheManager)
{
this.cacheManager = cacheManager;
}
}

总结

看了Ehcache的相关文档后,发现其非常强大,而且使用起来非常简单,这里只是真对项目中的特定需求做了简单的使用,关于性能参数调优还有待优化完善,后期可能会用到分布式,集群等应用,使用的时候再进行总结学习。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器